diff --git a/swh/web/archive_coverage/templates/archive-coverage.html b/swh/web/archive_coverage/templates/archive-coverage.html index d89444e0..3d236351 100644 --- a/swh/web/archive_coverage/templates/archive-coverage.html +++ b/swh/web/archive_coverage/templates/archive-coverage.html @@ -1,168 +1,170 @@ {% comment %} Copyright (C) 2015-2022 The Software Heritage developers See the AUTHORS file at the top-level directory of this distribution License: GNU Affero General Public License version 3, or any later version See top-level LICENSE file for more information {% endcomment %} {% load js_reverse %} {% load static %} {% load render_bundle from webpack_loader %} {% include "includes/favicon.html" %} Software Heritage archive coverage {% render_bundle 'vendors' %} {% render_bundle 'webapp' %}

A significant amount of source code has already been ingested in the Software Heritage archive. It notably includes the following software origins.

{% for origins_type, origins_data in origins.items %}
{{ origins_type }}

{{ origins_data.info | safe }}

{% for origins in origins_data.origins %}
{% with 'img/logos/'|add:origins.type.lower|add:'.png' as png_logo %} {% endwith %}
{% if "instances" in origins %} {% for instance, visit_types in origins.instances.items %} {% for visit_type, data in visit_types.items %} {% if data.count %} {% endif %} {% endfor %} {% endfor %} {% else %} {% for visit_type, search_url in origins.search_urls.items %} {% endfor %} {% endif %}
instance type count search
{{ instance }} {{ visit_type }} {{ data.count }} {% if data.search_url %} {% endif %}
instance type search
{{ origins.type }} {{ visit_type }} {% if search_url %} {% endif %}
{% endfor %}
{% endfor %}
- JavaScript license information + {% if "swh.web.jslicenses" in SWH_DJANGO_APPS %} + JavaScript license information + {% endif %} diff --git a/swh/web/browse/templates/browse-iframe.html b/swh/web/browse/templates/browse-iframe.html index eb479797..893c347e 100644 --- a/swh/web/browse/templates/browse-iframe.html +++ b/swh/web/browse/templates/browse-iframe.html @@ -1,182 +1,184 @@ {% comment %} Copyright (C) 2021-2022 The Software Heritage developers See the AUTHORS file at the top-level directory of this distribution License: GNU Affero General Public License version 3, or any later version See top-level LICENSE file for more information {% endcomment %} {% load static %} {% load render_bundle from webpack_loader %} {% load swh_templatetags %} Software Heritage archived object {% render_bundle 'vendors' %} {% render_bundle 'webapp' %} {% render_bundle 'browse' %}
{% include "includes/show-swhids.html" %}
Software Heritage
Navigating in
{% if swhid != focus_swhid %}
Reset view
{% endif %} View in the archive
{% if error_code != 200 %} {% include "includes/http-error.html" %} {% elif object_type == "cnt" %} {% include "includes/content-display.html" %} {% elif object_type == "dir" %} {% include "includes/directory-display.html" %} {% endif %}
- - JavaScript license information - + {% if "swh.web.jslicenses" in SWH_DJANGO_APPS %} + + JavaScript license information + + {% endif %} {% if object_type == "cnt" %} {% endif %} diff --git a/swh/web/config.py b/swh/web/config.py index ad08167b..1f4377d9 100644 --- a/swh/web/config.py +++ b/swh/web/config.py @@ -1,239 +1,240 @@ # Copyright (C) 2017-2022 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information import os from typing import Any, Dict from swh.core import config from swh.counters import get_counters from swh.indexer.storage import get_indexer_storage from swh.scheduler import get_scheduler from swh.search import get_search from swh.storage import get_storage from swh.vault import get_vault from swh.web import settings SWH_WEB_SERVER_NAME = "archive.softwareheritage.org" SWH_WEB_INTERNAL_SERVER_NAME = "archive.internal.softwareheritage.org" SWH_WEB_STAGING_SERVER_NAMES = [ "webapp.staging.swh.network", "webapp.internal.staging.swh.network", ] SETTINGS_DIR = os.path.dirname(settings.__file__) DEFAULT_CONFIG = { "allowed_hosts": ("list", []), "storage": ( "dict", { "cls": "remote", "url": "http://127.0.0.1:5002/", "timeout": 10, }, ), "indexer_storage": ( "dict", { "cls": "remote", "url": "http://127.0.0.1:5007/", "timeout": 1, }, ), "counters": ( "dict", { "cls": "remote", "url": "http://127.0.0.1:5011/", "timeout": 1, }, ), "search": ( "dict", { "cls": "remote", "url": "http://127.0.0.1:5010/", "timeout": 10, }, ), "search_config": ( "dict", { "metadata_backend": "swh-indexer-storage", }, # or "swh-search" ), "log_dir": ("string", "/tmp/swh/log"), "debug": ("bool", False), "serve_assets": ("bool", False), "host": ("string", "127.0.0.1"), "port": ("int", 5004), "secret_key": ("string", "development key"), # do not display code highlighting for content > 1MB "content_display_max_size": ("int", 5 * 1024 * 1024), "snapshot_content_max_size": ("int", 1000), "throttling": ( "dict", { "cache_uri": None, # production: memcached as cache (127.0.0.1:11211) # development: in-memory cache so None "scopes": { "swh_api": { "limiter_rate": {"default": "120/h"}, "exempted_networks": ["127.0.0.0/8"], }, "swh_api_origin_search": { "limiter_rate": {"default": "10/m"}, "exempted_networks": ["127.0.0.0/8"], }, "swh_vault_cooking": { "limiter_rate": {"default": "120/h", "GET": "60/m"}, "exempted_networks": ["127.0.0.0/8"], }, "swh_save_origin": { "limiter_rate": {"default": "120/h", "POST": "10/h"}, "exempted_networks": ["127.0.0.0/8"], }, "swh_api_origin_visit_latest": { "limiter_rate": {"default": "700/m"}, "exempted_networks": ["127.0.0.0/8"], }, }, }, ), "vault": ( "dict", { "cls": "remote", "args": { "url": "http://127.0.0.1:5005/", }, }, ), "scheduler": ("dict", {"cls": "remote", "url": "http://127.0.0.1:5008/"}), "development_db": ("string", os.path.join(SETTINGS_DIR, "db.sqlite3")), "test_db": ("dict", {"name": "swh-web-test"}), "production_db": ("dict", {"name": "swh-web"}), "deposit": ( "dict", { "private_api_url": "https://deposit.softwareheritage.org/1/private/", "private_api_user": "swhworker", "private_api_password": "some-password", }, ), "e2e_tests_mode": ("bool", False), "es_workers_index_url": ("string", ""), "history_counters_url": ( "string", ( "http://counters1.internal.softwareheritage.org:5011" "/counters_history/history.json" ), ), "client_config": ("dict", {}), "keycloak": ("dict", {"server_url": "", "realm_name": ""}), "graph": ( "dict", { "server_url": "http://graph.internal.softwareheritage.org:5009/graph/", "max_edges": {"staff": 0, "user": 100000, "anonymous": 1000}, }, ), "status": ( "dict", { "server_url": "https://status.softwareheritage.org/", "json_path": "1.0/status/578e5eddcdc0cc7951000520", }, ), "counters_backend": ("string", "swh-storage"), # or "swh-counters" "staging_server_names": ("list", SWH_WEB_STAGING_SERVER_NAMES), "instance_name": ("str", "archive-test.softwareheritage.org"), "give": ("dict", {"public_key": "", "token": ""}), "features": ("dict", {"add_forge_now": True}), "add_forge_now": ("dict", {"email_address": "add-forge-now@example.com"}), "swh_extra_django_apps": ( "list", [ "swh.web.inbound_email", "swh.web.add_forge_now", "swh.web.mailmap", "swh.web.save_code_now", "swh.web.deposit", "swh.web.badges", "swh.web.archive_coverage", "swh.web.metrics", "swh.web.banners", + "swh.web.jslicenses", ], ), } swhweb_config: Dict[str, Any] = {} def get_config(config_file="web/web"): """Read the configuration file `config_file`. If an environment variable SWH_CONFIG_FILENAME is defined, this takes precedence over the config_file parameter. In any case, update the app with parameters (secret_key, conf) and return the parsed configuration as a dict. If no configuration file is provided, return a default configuration. """ if not swhweb_config: config_filename = os.environ.get("SWH_CONFIG_FILENAME") if config_filename: config_file = config_filename cfg = config.load_named_config(config_file, DEFAULT_CONFIG) swhweb_config.update(cfg) config.prepare_folders(swhweb_config, "log_dir") if swhweb_config.get("search"): swhweb_config["search"] = get_search(**swhweb_config["search"]) else: swhweb_config["search"] = None swhweb_config["storage"] = get_storage(**swhweb_config["storage"]) swhweb_config["vault"] = get_vault(**swhweb_config["vault"]) swhweb_config["indexer_storage"] = get_indexer_storage( **swhweb_config["indexer_storage"] ) swhweb_config["scheduler"] = get_scheduler(**swhweb_config["scheduler"]) swhweb_config["counters"] = get_counters(**swhweb_config["counters"]) return swhweb_config def search(): """Return the current application's search.""" return get_config()["search"] def storage(): """Return the current application's storage.""" return get_config()["storage"] def vault(): """Return the current application's vault.""" return get_config()["vault"] def indexer_storage(): """Return the current application's indexer storage.""" return get_config()["indexer_storage"] def scheduler(): """Return the current application's scheduler.""" return get_config()["scheduler"] def counters(): """Return the current application's counters.""" return get_config()["counters"] diff --git a/swh/web/jslicenses/__init__.py b/swh/web/jslicenses/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/swh/web/templates/misc/jslicenses.html b/swh/web/jslicenses/templates/jslicenses.html similarity index 98% rename from swh/web/templates/misc/jslicenses.html rename to swh/web/jslicenses/templates/jslicenses.html index 3a343ff3..40f114a6 100644 --- a/swh/web/templates/misc/jslicenses.html +++ b/swh/web/jslicenses/templates/jslicenses.html @@ -1,77 +1,77 @@ -{% extends "../layout.html" %} +{% extends "layout.html" %} {% comment %} Copyright (C) 2019 The Software Heritage developers See the AUTHORS file at the top-level directory of this distribution License: GNU Affero General Public License version 3, or any later version See top-level LICENSE file for more information {% endcomment %} {% load swh_templatetags %} {% block title %}JavaScript license information{% endblock %} {% block navbar-content %}

JavaScript license information

{% endblock %} {% block content %}

This page states the licenses of all the JavaScript files loaded by that web application. The loaded JavaScript files correspond to bundles concatenating multiple source files. You can find the details of the content of each bundle in the Web Labels table below.

{% for jsasset, bundled_js_srcs in jslicenses_data %} {% endfor %}
Script Licenses Sources
{% if jsasset|split:"/"|last %} {{ jsasset | split:"/" | last }} {% else %} {{ jsasset }} {% endif %} {% for js_src in bundled_js_srcs %} {% for js_license in js_src.licenses %} {{ js_license.name }} {% if js_license.copy_url %} (view) {% endif %} {% if not forloop.last %}
{% endif %} {% endfor %} {% if not forloop.last %}

{% endif %} {% endfor %}
{% for js_src in bundled_js_srcs %} {{ js_src.id }} {% for js_license in js_src.licenses %} {% if not forloop.last %}
{% endif %} {% endfor %} {% if not forloop.last %}

{% endif %} {% endfor %}
{% endblock %} diff --git a/swh/web/jslicenses/urls.py b/swh/web/jslicenses/urls.py new file mode 100644 index 00000000..2e5a9597 --- /dev/null +++ b/swh/web/jslicenses/urls.py @@ -0,0 +1,26 @@ +# Copyright (C) 2022 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU Affero General Public License version 3, or any later version +# See top-level LICENSE file for more information + +import json + +from django.contrib.staticfiles import finders +from django.shortcuts import render +from django.urls import re_path as url + + +def jslicenses(request): + jslicenses_file = finders.find("jssources/jslicenses.json") + jslicenses_data = {} + if jslicenses_file is not None: + jslicenses_data = json.load(open(jslicenses_file)) + jslicenses_data = sorted( + jslicenses_data.items(), key=lambda item: item[0].split("/")[-1] + ) + return render(request, "jslicenses.html", {"jslicenses_data": jslicenses_data}) + + +urlpatterns = [ + url(r"^jslicenses/$", jslicenses, name="jslicenses"), +] diff --git a/swh/web/misc/urls.py b/swh/web/misc/urls.py index 15551397..efebe0b9 100644 --- a/swh/web/misc/urls.py +++ b/swh/web/misc/urls.py @@ -1,98 +1,86 @@ # Copyright (C) 2019-2022 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information import json import requests -from django.contrib.staticfiles import finders from django.http import JsonResponse -from django.shortcuts import render from django.urls import re_path as url from swh.web.config import get_config from swh.web.utils import archive from swh.web.utils.exc import sentry_capture_exception -def _jslicenses(request): - jslicenses_file = finders.find("jssources/jslicenses.json") - jslicenses_data = json.load(open(jslicenses_file)) - jslicenses_data = sorted( - jslicenses_data.items(), key=lambda item: item[0].split("/")[-1] - ) - return render(request, "misc/jslicenses.html", {"jslicenses_data": jslicenses_data}) - - def _stat_counters(request): stat_counters = archive.stat_counters() url = get_config()["history_counters_url"] stat_counters_history = {} try: response = requests.get(url, timeout=5) stat_counters_history = json.loads(response.text) except Exception as exc: sentry_capture_exception(exc) counters = { "stat_counters": stat_counters, "stat_counters_history": stat_counters_history, } return JsonResponse(counters) urlpatterns = [ - url(r"^jslicenses/$", _jslicenses, name="jslicenses"), url(r"^stat_counters/$", _stat_counters, name="stat-counters"), ] # when running end to end tests through cypress, declare some extra # endpoints to provide input data for some of those tests if get_config()["e2e_tests_mode"]: from swh.web.tests.views import ( get_content_code_data_all_exts, get_content_code_data_all_filenames, get_content_code_data_by_ext, get_content_code_data_by_filename, get_content_other_data_by_ext, ) urlpatterns.append( url( r"^tests/data/content/code/extension/(?P.+)/$", get_content_code_data_by_ext, name="tests-content-code-extension", ) ) urlpatterns.append( url( r"^tests/data/content/other/extension/(?P.+)/$", get_content_other_data_by_ext, name="tests-content-other-extension", ) ) urlpatterns.append( url( r"^tests/data/content/code/extensions/$", get_content_code_data_all_exts, name="tests-content-code-extensions", ) ) urlpatterns.append( url( r"^tests/data/content/code/filename/(?P.+)/$", get_content_code_data_by_filename, name="tests-content-code-filename", ) ) urlpatterns.append( url( r"^tests/data/content/code/filenames/$", get_content_code_data_all_filenames, name="tests-content-code-filenames", ) ) diff --git a/swh/web/templates/layout.html b/swh/web/templates/layout.html index b1254a8d..479d3a79 100644 --- a/swh/web/templates/layout.html +++ b/swh/web/templates/layout.html @@ -1,325 +1,327 @@ {% comment %} Copyright (C) 2015-2022 The Software Heritage developers See the AUTHORS file at the top-level directory of this distribution License: GNU Affero General Public License version 3, or any later version See top-level LICENSE file for more information {% endcomment %} {% load js_reverse %} {% load static %} {% load render_bundle from webpack_loader %} {% load swh_templatetags %} {% block title %}{% endblock %} {% render_bundle 'vendors' %} {% render_bundle 'webapp' %} {% render_bundle 'guided_tour' %} {{ request.user.is_authenticated|json_script:"swh_user_logged_in" }} {% include "includes/favicon.html" %} {% block header %}{% endblock %} {% if swh_web_prod %} {% endif %}
{% if "swh.web.banners" in SWH_DJANGO_APPS %}
{% include "hiring-banner.html" %}
{% endif %}
{% if swh_web_staging %}
Staging
v{{ swh_web_version }}
{% elif swh_web_dev %}
Development
v{{ swh_web_version|split:"+"|first }}
{% endif %} {% block content %}{% endblock %}
{% include "includes/global-modals.html" %}
back to top
diff --git a/swh/web/tests/jslicenses/__init__.py b/swh/web/tests/jslicenses/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/swh/web/tests/jslicenses/test_app.py b/swh/web/tests/jslicenses/test_app.py new file mode 100644 index 00000000..a0b6c114 --- /dev/null +++ b/swh/web/tests/jslicenses/test_app.py @@ -0,0 +1,35 @@ +# Copyright (C) 2022 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU Affero General Public License version 3, or any later version +# See top-level LICENSE file for more information + +import pytest + +from django.urls import get_resolver + +from swh.web.jslicenses.urls import urlpatterns +from swh.web.tests.django_asserts import assert_contains, assert_not_contains +from swh.web.tests.helpers import check_html_get_response +from swh.web.utils import reverse + + +@pytest.mark.django_db +def test_jslicenses_deactivate(client, django_settings): + """Check jslicenses feature is deactivated when the swh.web.jslicenses django + application is not in installed apps.""" + + url = reverse("swh-web-homepage") + + resp = check_html_get_response(client, url, status_code=200) + assert_contains(resp, "jslicense") + + django_settings.SWH_DJANGO_APPS = [ + app for app in django_settings.SWH_DJANGO_APPS if app != "swh.web.jslicenses" + ] + + resp = check_html_get_response(client, url, status_code=200) + assert_not_contains(resp, "jslicense") + + jslicenses_view_names = set(urlpattern.name for urlpattern in urlpatterns) + all_view_names = set(get_resolver().reverse_dict.keys()) + assert jslicenses_view_names & all_view_names == set() diff --git a/swh/web/tests/jslicenses/test_jslicenses.py b/swh/web/tests/jslicenses/test_jslicenses.py new file mode 100644 index 00000000..6d43a008 --- /dev/null +++ b/swh/web/tests/jslicenses/test_jslicenses.py @@ -0,0 +1,14 @@ +# Copyright (C) 2022 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU Affero General Public License version 3, or any later version +# See top-level LICENSE file for more information + +from swh.web.tests.helpers import check_html_get_response +from swh.web.utils import reverse + + +def test_js_licenses(client): + url = reverse("jslicenses") + check_html_get_response( + client, url, status_code=200, template_used="jslicenses.html" + )